package com.tzy.rpc.transport;/**
 * @description:
 * @Author HP
 * @create 2022/3/14 16:30
 */

import com.tzy.rpc.entity.RpcRequest;
import com.tzy.rpc.entity.RpcResponse;
import com.tzy.rpc.transport.netty.client.NettyClient;
import com.tzy.rpc.transport.socket.client.SocketClient;
import com.tzy.rpc.util.RpcMessageChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * @author HP
 * @create 2022-03-14 16:30
 * @desc 客户端动态代理类，通过动态代理调用服务
 **/
public class RpcClientProxy implements InvocationHandler {
    private static final Logger logger = LoggerFactory.getLogger(RpcClientProxy.class);
    private RpcClient client;

    //传递host和port来指明服务端的位置
    public RpcClientProxy(RpcClient client){
       this.client=client;
    }

    //抑制编译器产生警告信息
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz){
        //创建代理对象
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //客户端向服务端传输的对象,Builder模式生成
        RpcRequest rpcRequest = RpcRequest.builder()
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameters(args)
                .paraTypes(method.getParameterTypes())
                .requestId(UUID.randomUUID().toString())
                .heartBeat(false)
                .build();
        //进行远程调用的客户端
        RpcResponse rpcResponse = null;
        if (client instanceof NettyClient){
            logger.info("NettyClient被代理");
            try {
                //异步获取调用结果
                CompletableFuture<RpcResponse> completableFuture = (CompletableFuture<RpcResponse>)client.sendRequest(rpcRequest);
                rpcResponse=completableFuture.get();
            }catch (Exception e){
                logger.error("方法调用请求发送失败", e);
                return null;
            }
        }else if (client instanceof SocketClient){
            logger.info("SocketClient被代理");
            rpcResponse=((RpcResponse)client.sendRequest(rpcRequest));
        }
        RpcMessageChecker.check(rpcRequest, rpcResponse);
        return rpcResponse.getData();
    }
}
